import javassist.*;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

/**
 * @Author: huangjc
 * @Date: Created in 2018/12/28 16:19
 */
public class Example1 {
    public static void main(String[] args) throws NotFoundException, CannotCompileException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
        //Class池
        ClassPool pool = ClassPool.getDefault();
        //Creates a new public class
        CtClass cls = pool.makeClass("cn.ibm.com.TestClass");

        //添加私有成员name及其getter&setter方法
        //第一个参数是类型，第二个参数是参数名称，第三个是参数要加到哪个类里
        CtField param = new CtField(pool.get("java.lang.String"), "name", cls);
        //添加一个setter方法
        cls.addMethod(CtNewMethod.setter("setName", param));
        //添加一个getter方法
        cls.addMethod(CtNewMethod.getter("getName", param));
        cls.addField(param, CtField.Initializer.constant(""));

        //添加无参的构造体
        CtConstructor constructor = new CtConstructor(new CtClass[]{}, cls);
        constructor.setBody("{name=\"Brant\";}");
        cls.addConstructor(constructor);

        //添加有参的构造体
        constructor = new CtConstructor(new CtClass[]{pool.get("java.lang.String")}, cls);
        /*
        $0表示this对象，$0.name即是this.name
        $1，$2，...：方法参数列表，顺序是一一对应的；
        $_：返回值
        $r，$w：用于类型转换表达式里，否则转换不生效而编译失败
         */
        constructor.setBody("{$0.name=$1;}");
        cls.addConstructor(constructor);

        //拿到类的字节码
        Class clz = cls.toClass();
        System.out.println(clz);

        //反射创建对象
        Object obj = clz.newInstance();

        //getter拿到name值
        Method getter = clz.getMethod("getName");
        System.out.println(getter.invoke(obj));

        //setter设置name值，再取出来
        Method setter = clz.getMethod("setName", java.lang.String.class);
        setter.invoke(obj, "张三");
        System.out.println(getter.invoke(obj));

        //使用有参构造函数
        obj = clz.getConstructor(String.class).newInstance("李四");
        System.out.println(getter.invoke(obj));
    }
}
